﻿// Log.cpp : 定义静态库的函数。
//

#include "pch.h"
#include "framework.h"

#include <fstream>
#include <iostream>
#include <Windows.h>
#include <direct.h>
#include <iomanip>
#include <chrono>
#include <sstream>
#include <io.h>

#define _Print_
#pragma warning( disable : 4996 )
std::ofstream LogFileHandle;
std::string LogPath;

bool OpenLogService = false;
bool PrintConsole;
bool WriteFileStatus = false;

typedef enum LogType {
    _Log_Log,
    _LOG_DEBUG,
    _LOG_INFO,
    _LOG_WARNING,
    _LOG_ERROR,
};

void PrintColorText(
    _In_ WORD forecolor,
    _In_ std::string strings
);
std::string ParseLogString(
    LogType LT,
    std::string str
);
std::string LogGetDateString();
void WriteLog(
    _In_ LogType LT,
    _In_ std::string strings
);
std::string LogGetDateStringChinese();
std::string LogGetDateStringPath();
std::string MsFillZero(long long mileseconds);

void LogDebug(std::string Message) {
#ifdef _DEBUG
    if (!OpenLogService) {
        throw "Log Service is not opened.";
    }
    WriteLog(LogType::_LOG_DEBUG, Message);
#endif
}

void LogInfo(std::string Message) {
    if (!OpenLogService) {
        throw "Log Service is not opened.";
    }
    WriteLog(LogType::_LOG_INFO, Message);
}

void LogWarning(std::string Message) {
    if (!OpenLogService) {
        throw "Log Service is not opened.";
    }
    WriteLog(LogType::_LOG_WARNING, Message);
}

void LogError(std::string Message) {
    if (!OpenLogService) {
        throw "Log Service is not opened.";
    }
    WriteLog(LogType::_LOG_ERROR, Message);
}

//启动Log服务
bool LogStartService(
    std::string Title
)
{
    //获取程序运行路径
    char WorkDirChar[512] = { 0 };
    _getcwd(WorkDirChar, sizeof(WorkDirChar) - 1);

    std::string dir = WorkDirChar;
    dir += "\\log"; //Log目录

    //获取程序运行目录
    const int MAXPATH = 250;
    char buffer[MAXPATH];
    _getcwd(buffer, MAXPATH);

    //const wchar_t* wt = reinterpret_cast<const wchar_t*>(dir.c_str());

    if (_access(dir.c_str(), 0) == -1) { //判断该文件夹是否存在

        int flag = _mkdir(dir.c_str());  //Windows创建文件夹
        if (flag == 0) {  //创建成功
            //std::cout << "Create directory successfully." << std::endl;
        }
        else { //创建失败
#ifdef _Print_
            std::cout << "Fail to create directory." << std::endl;
#endif
            throw std::exception("Fail to create directory.");
        }
    }

    //拼接log路径
    std::string LogFilePathA = dir + "\\Log_" + LogGetDateStringPath() + ".log";
    std::cout << LogFilePathA << std::endl;

    //std::string LogFilePathA=dir +"\\Log"+ ".log";

    /*
std::cout << LogFilePathA.c_str() << std::endl;
HANDLE fHandle = CreateFile(
        LogFilePathA.c_str(),
        GENERIC_READ|GENERIC_WRITE,
        FILE_SHARE_READ,
        NULL,
        CREATE_ALWAYS,
        FILE_ATTRIBUTE_NORMAL,
        0
        );
*/

    std::fstream fs;
    fs.open(LogFilePathA, std::ios::out);
    fs.close();

    WriteFileStatus = true;
#ifdef _Print_
    //std::cout << GetLastError() << std::endl;
#endif
    //打开log文件
    LogFileHandle.open(LogFilePathA, std::ios::app | std::ios::out);

    if (!LogFileHandle.is_open()) {
        SetLastError(0b100000010010);
#ifdef _Print_
        std::cout << "Error:" << LogFileHandle.rdstate() << std::endl;
#endif
        return false;
    }

    std::string LogCreateDate = LogGetDateString();

    OpenLogService = true;
    LogPath = LogFilePathA;

    WriteLog(LogType::_Log_Log, "====================");
    WriteLog(LogType::_Log_Log, "AZPEP SysRi Tool 日志记录工具 v1.0");
    WriteLog(LogType::_Log_Log, "开发者：AZPEP_BiliBili");
    WriteLog(LogType::_Log_Log, "Copyright 2024-2024");
    WriteLog(LogType::_Log_Log, "---------------------");
    WriteLog(LogType::_Log_Log, "日志文件绝对路径：" + LogFilePathA);
    WriteLog(LogType::_Log_Log, "日志文件创建时间：" + LogCreateDate);
    if (Title != "") {
        WriteLog(LogType::_Log_Log, "---------------------");
        WriteLog(LogType::_Log_Log, Title);
    }
    WriteLog(LogType::_Log_Log, "====================");
    WriteLog(LogType::_Log_Log, "!!! 日志于 " + LogGetDateStringChinese() + " 开始记录 !!!");
    WriteLog(LogType::_Log_Log, "+++++++++++++++++++++++\n");

    return true;
}

//启动Log服务(可指定路径)
bool LogStartServiceEx(
    std::string LogFilePath,
    std::string Title
)
{

    //拼接log路径
    std::string LogFilePathA = LogFilePath;
    if (LogFilePath != "") {
        //std::string LogFilePathA=dir +"\\Log"+ ".log";

        /*
    std::cout << LogFilePathA.c_str() << std::endl;
    HANDLE fHandle = CreateFile(
            LogFilePathA.c_str(),
            GENERIC_READ|GENERIC_WRITE,
            FILE_SHARE_READ,
            NULL,
            CREATE_ALWAYS,
            FILE_ATTRIBUTE_NORMAL,
            0
            );
    */

        std::fstream fs;
        fs.open(LogFilePathA, std::ios::out);
        fs.close();

        WriteFileStatus = true;
    }
    else {
        WriteFileStatus = false;
    }
#ifdef _Print_
    //std::cout << GetLastError() << std::endl;
#endif
    //打开log文件
    LogFileHandle.open(LogFilePathA, std::ios::app | std::ios::out);

    if (!LogFileHandle.is_open()) {
        SetLastError(0b100000010010);
#ifdef _Print_
        std::cout << "Error:" << LogFileHandle.rdstate() << std::endl;
#endif
        return false;
    }

    std::string LogCreateDate = LogGetDateString();

    OpenLogService = true;
    LogPath = LogFilePathA;

    WriteLog(LogType::_Log_Log, "====================");
    WriteLog(LogType::_Log_Log, "AZPEP SysRi Tool 日志记录工具 v1.0");
    WriteLog(LogType::_Log_Log, "开发者：AZPEP_BiliBili");
    WriteLog(LogType::_Log_Log, "Copyright 2024-2024");
    WriteLog(LogType::_Log_Log, "---------------------");
    WriteLog(LogType::_Log_Log, "日志文件绝对路径：" + LogFilePathA);
    WriteLog(LogType::_Log_Log, "日志文件创建时间：" + LogCreateDate);
    if (Title != "") {
        WriteLog(LogType::_Log_Log, "---------------------");
        WriteLog(LogType::_Log_Log, Title);
    }
    WriteLog(LogType::_Log_Log, "====================");
    WriteLog(LogType::_Log_Log, "!!! 日志于 " + LogGetDateStringChinese() + " 开始记录 !!!");
    WriteLog(LogType::_Log_Log, "+++++++++++++++++++++++\n");

    return true;
}

//停止日志服务
void LogStopService() {
    WriteLog(LogType::_Log_Log, "+++++++++++++++++++++++");
    WriteLog(LogType::_Log_Log, "!!! 日志于 " + LogGetDateStringChinese() + " 停止记录 !!!");
    LogFileHandle.close();
    LogPath = "";
    WriteFileStatus = false;
    OpenLogService = false;
}

//获取当前日志路径
std::string LogGetFileFullPath() {
    return LogPath;
}

//检查日志服务是否开启，true为开启，false为未开启
bool LogCheckServiceOpenStatus() {
    return OpenLogService;
}

//检查日志是否可写
bool LogCheckWriteFileEnable() {
    return WriteFileStatus;
}

//写入日志
void WriteLog(
    _In_ LogType LT,
    _In_ std::string strings
)
{
    std::string ss = ParseLogString(LT, strings);
#ifdef _Print_
    WORD ForeColor;

    switch (LT) {
    case LogType::_Log_Log:
        ForeColor = FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_RED | FOREGROUND_INTENSITY;  //白色
        break;
    case LogType::_LOG_DEBUG:
        ForeColor = FOREGROUND_GREEN | FOREGROUND_INTENSITY; //亮绿色
        break;
    case LogType::_LOG_INFO:
        ForeColor = FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY;  //青色
        break;
    case LogType::_LOG_WARNING:
        ForeColor = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY; //黄色
        break;
    case LogType::_LOG_ERROR:
        ForeColor = FOREGROUND_RED | FOREGROUND_INTENSITY; //亮红色
        break;
    }

    PrintColorText(ForeColor, ss);
#endif
    if (WriteFileStatus) {
        LogFileHandle << ss << std::endl;
    }
}

//打印彩色文字
void PrintColorText(
    _In_ WORD forecolor,
    _In_ std::string strings
) {
    HANDLE hCon = GetStdHandle(STD_OUTPUT_HANDLE);
    SetConsoleTextAttribute(hCon, forecolor);
    std::cout << strings << std::endl;
    SetConsoleTextAttribute(hCon, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY);
}

std::string ParseLogString(LogType LT, std::string str) {
    std::string ss = "[" + LogGetDateString() + "]";
    switch (LT) {
    case LogType::_Log_Log:
        ss = ss + "[  LOG  ]";
        break;
    case LogType::_LOG_DEBUG:
        ss = ss + "[ DEBUG ]";
        break;
    case LogType::_LOG_INFO:
        ss = ss + "[  INFO ]";
        break;
    case LogType::_LOG_WARNING:
        ss = ss + "[WARNING]";
        break;
    case LogType::_LOG_ERROR:
        ss = ss + "[ ERROR ]";
        break;
    }

    ss += "   " + str;
    return ss;
}
//获取当前时间
std::string LogGetDateString() {
    auto time = std::chrono::system_clock::now();
    auto t = std::chrono::system_clock::to_time_t(time);

    std::stringstream ss;
    ss << std::put_time(localtime(&t), "%Y-%m-%d %H:%M:%S");

    auto milesec = std::chrono::duration_cast<std::chrono::microseconds>(time.time_since_epoch());
    //ss << ":" << milesec_str.substr(0, 4);
    //ss << ":" << MsFillZero(milesec.count());
    ss << ":" << MsFillZero((int)floor(milesec.count())).substr(MsFillZero((int)floor(milesec.count())).length()-6, 3);

    return ss.str();
}

std::string LogGetDateStringChinese() {
    auto tt = std::chrono::system_clock::now();
    auto t = std::chrono::system_clock::to_time_t(tt);
    time_t time_seconds = time(0);

    std::stringstream ss;
    ss << std::put_time(localtime(&t), "%Y年%m月%d日 %H:%M:%S");

    auto milesec = std::chrono::duration_cast<std::chrono::microseconds>(tt.time_since_epoch());
    ss << ":" << MsFillZero((int)floor(milesec.count())).substr(MsFillZero((int)floor(milesec.count())).length() - 6, 3);

    return ss.str();
}

std::string LogGetDateStringPath() {
    auto time = std::chrono::system_clock::now();
    auto t = std::chrono::system_clock::to_time_t(time);

    std::stringstream ss;
    ss << std::put_time(localtime(&t), "%Y-%m-%d_%H-%M-%S");

    auto milesec = std::chrono::duration_cast<std::chrono::microseconds>(time.time_since_epoch());
    //ss << "-" << milesec_str.substr(0, 4);
    ss << "-" << MsFillZero((int)floor(milesec.count())).substr(MsFillZero((int)floor(milesec.count())).length() - 6, 3);

    return ss.str();
}

std::string MsFillZero(long long mileseconds) {
    std::stringstream ss;

    for (int i = 0; i < 8-std::to_string(mileseconds).length(); i++) {
        ss << "0";
    }

    ss << std::to_string(mileseconds);

    return ss.str();
}

std::string Double_2f(double num) {
    char c[40];

    sprintf_s(c, 40, "%.2f", num);

    std::stringstream ss;
    ss << c;

    return ss.str();
}